/*
 * FunctionProtoAst.cpp
 *
 *  Created on: 19 Nov 2010
 *      Author: kn308
 */

#include <MAlice/Parser/location.hh>
#include "FunctionProtoAst.h"
#include <MAlice/Ast/ListAst.h>
#include <MAlice/Ast/FunctionParameterAst.h>

namespace MAlice
{

FunctionProtoAst::FunctionProtoAst(location loc, const string& name, TypeAst* returnType,
		ListAst* parameters) : Ast(loc),
	mName(name), mReturnType(returnType), mParameters(parameters)
{
	MALICE_TRACE;
}

FunctionProtoAst::~FunctionProtoAst()
{
	MALICE_TRACE;
}

llvm::Value* FunctionProtoAst::generate()
{
	MALICE_TRACE;
	Codegen* g = Codegen::get();

	vector<const Type* > argTypes;
	vector<Ast*> params = mParameters->getChildren();
	for (vector<Ast*>::iterator i = params.begin(); i != params.end(); i++)
	{
		FunctionParameterAst* param = reinterpret_cast<FunctionParameterAst*>(*i);
		argTypes.push_back(param->getType()->type());
	}

	FunctionType* FT = FunctionType::get(mReturnType->type(), argTypes, false);
	Function*     F  = Function::Create(FT, Function::ExternalLinkage, mName, g->getModule());
	BasicBlock*   BB = BasicBlock::Create(g->getContext(), "entry", F);
	Builder*      builder = g->getBuilder();

	// create alloca for the function arguments
	builder->SetInsertPoint(BB);
	Function::arg_iterator arg = F->arg_begin();
	for (vector<Ast*>::iterator i = params.begin(); i != params.end() && arg != F->arg_end(); i++, arg++)
	{
		FunctionParameterAst* param = reinterpret_cast<FunctionParameterAst*>(*i);

		const string& name = param->getName();
		const Type*   type = param->getType()->type();

		arg->setName(name);

		// create the argument alloca and push it on the variable table
		Value* argAlloca = builder->CreateAlloca(type, NULL, Twine(arg->getName()) + ".param");
		builder->CreateStore(arg, argAlloca, false);
		g->pushVar(name, argAlloca);
	}

	return F;
}

}
